#include "ConfigReader.h"
#include <fstream>
#include <boost/algorithm/string/split.hpp>
#ifdef _WIN32
#include <Windows.h>
#endif
#include <algorithm>
#include <functional> // for trim function
#include <cctype> // for trim function
#include <sstream> // for split function
#include <vector>
#include <iostream>

ConfigReader::ConfigReader()
{}

// load configuration file
bool ConfigReader::load(std::string filePath)
{
	std::ifstream fin(filePath.c_str(), std::ios::in);

	if (!fin.is_open())
	{
		// file not found
#ifdef _WIN32
		SetLastError(404);
#endif
		return false;
	}
	// trim on left side of string
	auto trimLeft = [](std::string source)->std::string
	{
		source.erase(begin(source), std::find_if(begin(source), end(source), std::not1(std::ptr_fun<int, int>(std::isspace))));
		return source;
	};
	// trim on right side of string
	auto trimRight = [](std::string source)->std::string
	{
		source.erase(std::find_if(source.rbegin(), source.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), end(source));
		return source;
	};
	// trim on both left and right side of string
	auto trim = [&](std::string source)->std::string
	{
		return trimLeft(trimRight(source));
	};

	// split string by delim
//	auto split = [](std::string source, char delim) {
//		auto ss = std::stringstream(source);
//
//		std::vector<std::string> result;
//		std::string item;
//
//		while (std::getline(ss, item, delim))
//		{
//			if (item.length() > 0)
//			{
//				result.push_back(std::move(item));
//			}
//		}
//
//		return result;
//	};

	std::string lineContent;
	// read content of file
	size_t equalPos = -1; // position of '=' character
	std::string key; // key
	std::string value; // value of key
	// read file until meet end of file

	while (fin.good())
	{
		std::getline(fin, lineContent); // read by line
		if (lineContent.length() > 2)
		{
			lineContent = std::move(trim(lineContent));
			equalPos = lineContent.find('=', 0);
			if (equalPos != std::string::npos &&  lineContent.find('#') != 0)
			{
				// not a comment
				key = std::move(trim(lineContent.substr(0, equalPos))); // trim key
				value = lineContent.substr(equalPos + 1); // value of key
				properties.emplace(std::move(trim(key)), std::move(trim(value))); // add to properties map
			}
		}
	}

	fin.close(); // close stream

	return true;
}

// get property by name
std::string ConfigReader::getProperty(std::string propName)
{
	if (properties.find(propName) == end(properties))
		throw; // key not found

	return properties[propName];
}

// clear map and destroy resource
ConfigReader::~ConfigReader()
{
	properties.clear(); // clear map
}

